﻿using System;

using System.Collections.Generic;
using System.Text;
using PublicTransport.DAL;
using PublicTransport.Helpers;
using PublicTransport.Services.Enums;

namespace PublicTransport.Services
{
    /// <summary>  Druhý krok nájde zo vstupného zoznamu možných použiteľných liniek z A do B, tie
    /// 		   linky a také časy, ktoré vyhovujú kriériam.  </summary>
    public class Step2
    {
        TimeTableDao timeTable;

        public Step2(TimeTableDao dao)
        {
            timeTable = dao;
        }

        public class Transit : IComparable<Transit>
        {
            public int StationID { get; set; }
            public int LineWhichTakeYouHere { get; set; }
            public int Time { get; set; }
            public int ArrivalTime { get; set; }

            #region IComparable<Transit> Members

            public int CompareTo(Transit other)
            {
                return this.ArrivalTime.CompareTo(other.ArrivalTime);
            }

            #endregion
        }

        /*
        public List<List<Transit>> GetTimes(List<List<NodeInfo>> solutions, int time)
        {
            List<List<Transit>> resultTransit = new List<List<Transit>>();

            foreach (List<NodeInfo> alternative in solutions)
            {
                List<Line> tempResult = new List<Line>();
                List<Transit> transits = new List<Transit>();
                bool valid = true;
                int tempTime = time;
                for (int i = 0; i < alternative.Count; i++)
                {
                    Line line = null;
                    if ((i + 1) < alternative.Count)
                    {
                        line = timeTable.GetLineTime(alternative[i].StationId, tempTime, "n", 29, alternative[i + 1].ArrivalLines.ConvertAll(x => x.LineID));
                        if (line == null)
                        {
                            //TODO: Break for 
                            valid = false;
                        }
                        else
                        {
                            tempTime = line.Time + FindDistance(alternative, line.LineID);
                            //tempResult.Add(line);
                        }
                    }

                    Transit transit = new Transit();
                    transit.LineWhichTakeYouHere = line != null ? line.LineID : -1;
                    transit.StationID = alternative[i].StationId;
                    transit.Time = line != null ? line.Time : -1;

                    transits.Add(transit);

                }

                if (valid == true)
                {
                    resultTransit.Add(transits);
                }
            }

            return resultTransit;
        }
        */

        /// <summary>   Metóda, ktorá prejde zoznam z prvého kroku. Skontroluje, či je možné 
        /// 			použiť dané spoj do danej zastávky - či premáva v danom čase </summary>
        ///
        /// <param name="solutions">    Možné spoje, ktoré sa dajú použiť pri cestovaní </param>
        /// <param name="time">         Čas v ktorom cestujeme </param>
        /// <param name="dayType">      Typ ďna - víkend, pracovný, voľný </param>
        public List<List<Transit>> GetTimes2(List<List<NodeInfo>> solutions, int time, DayTypeEnum dayType)
        {
            List<List<Transit>> totalResult = new List<List<Transit>>();
            String dayTypeString=null;
            switch (dayType)
            {
                case DayTypeEnum.Work: dayTypeString = "n"; break;
                case DayTypeEnum.Weekend: dayTypeString = "f"; break;
                case DayTypeEnum.Holiday: dayTypeString = "h"; break;
                  
            }

            foreach (List<NodeInfo> alternative in solutions)
            {
                List<List<Transit>> tempResultTransit = new List<List<Transit>>();
                int i =0;
                int solutionTime = time;
                FindTimes(tempResultTransit, new List<Transit>(), alternative, ref solutionTime, ref i, new Dictionary<int, Line>(), dayTypeString);
                totalResult.AddRange(tempResultTransit);
            }


            //139
            return totalResult;
        }

        private bool FindTimes(List<List<Transit>> result, List<Transit> branchResult, List<NodeInfo> alternative, ref int time, ref int position, Dictionary<int, Line> usedLines, String dayTypeString)
        {
            bool valid = false;

                List<Line> lines = null;

                if ((position + 1) < alternative.Count)
                {

                    lines = timeTable.GetLineTimes(alternative[position].StationId, time, dayTypeString, 29, alternative[position + 1].ArrivalLines.ConvertAll(x => x.LineID));

                    if (lines == null || lines.Count==0)
                    {
                        //TODO: Break for
                        branchResult = null;
                        return false;
                    }
                    else
                    {
                        position++;
                        foreach (Line line in lines)
                        {
                            if (usedLines.ContainsKey(line.LineID) == false)
                            {
                                usedLines.Add(line.LineID, line);
                                List<Transit> b = branchResult.ConvertAll(delegate(Transit input) { return input; });
                                //TODO: merge these two rows later
                                int distance = FindDistance(alternative, line.LineID);
                                time = Helper.AddTime(line.Time, distance);

                                Transit transit = new Transit();
                                transit.LineWhichTakeYouHere = line != null ? line.LineID : -1;
                                transit.StationID = alternative[position].StationId;
                                transit.Time = line != null ? line.Time : -1;
                                transit.ArrivalTime = time;
                                b.Add(transit);

                                FindTimes(result, b, alternative, ref time, ref position, usedLines, dayTypeString);
                            }
                            else
                            {
                                
                            }
                        }
                    }
                }
                else
                {
                    if (branchResult != null && branchResult.Count==position)
                        result.Add(branchResult);
                }


                return valid;
            


        }

        public int FindDistance(List<NodeInfo> nodes, int lineId)
        {
            foreach (NodeInfo node in nodes)
            {
                foreach (Line lineNode in node.ArrivalLines)
                {
                    if (lineNode.LineID == lineId)
                    {
                        return lineNode.Distance;
                    }
                }
            }

            throw new Exception();
        }
    }

    public class TransitComparer : IComparer<List<PublicTransport.Services.Step2.Transit>>
    {

        #region IComparer<List<Transit>> Members

        public int Compare(List<PublicTransport.Services.Step2.Transit> x, List<PublicTransport.Services.Step2.Transit> y)
        {
            return x[x.Count-1].ArrivalTime.CompareTo(y[y.Count-1].ArrivalTime);
        }

        #endregion
    }
}
